# 一、map函数
# map函数接收的是两个参数，
# 一个是函数名，另外一个是序列，
# 其功能是将序列中的数值作为函数的参数依次传入到函数值中执行，然后再返回到列表中。返回值是一个迭代器对象。

# 给一个list 将list中每个元素的平方累加
list1 = [1, 2, 3, 4, 5]


# 计算一个数据的平方
def func(x):
    return x ** 2


print(map(func, list1))  # 输出 <map object at 0x000001FB4B2570D0> 迭代器对象
result = map(func, list1)
# 迭代器对象转换成list 输出
print(list(result))  # 输出 [1, 4, 9, 16, 25]

# map函数：一行代码完成上述功能。
print(list(map(lambda n: n ** 2, [1, 2, 3, 4, 5])))

# 二、reduce函数
# 也是一个参数为函数，另一个参数为序列对象（比如: list列表）。
# 其返回值为一个值而不是迭代器对象，故其常用与叠加、叠乘等等。
# reduce函数
# 函数详解：
# 1. function:一个有两个参数的函数
# 2. sequence:是一个序列，是一些数据的集合，或者是一组数据，可迭代对象
# 3. initial：可选，初始参数
# 4. 返回值：返回函数计算的结果
# 5. reduce()函数,使用function函数（有两个参数）先对集合中的sequence第 1、2 个元素进行操作，
# 如果存在initial参数，则将会以sequence中的第一个元素和initial作为参数，
# 用作调用，得到的结果再与sequence中的下一个数据用 function 函数运算，最后得到一个结果

# 简单案例 ：求一个列表的累加和
from functools import *

list_a = [1, 2, 3, 4, 5]


def func2(x, y):
    return x + y


print(reduce(func2, list_a))

# 上述案例:求一个列表的累加和. 用 lambda 表达式 + reduce 函数 完成
print(reduce(lambda x, y: x + y, list_a))

# 案例2： 给你很长的字符串， 统计字符串中每个单词出现的次数
str1 = 'hello world python hello python java hello python flask world'
# 第一步：字符串切割成list ['hello', 'world', 'python', 'hello', 'python', 'java', 'hello', 'python', 'flask', 'world']
lst = str1.split(' ')
# 第二步：转换成新的list，其中每个元素是一个map字典，key是字符串，value默认是1 ，累加这个value 1
ne_list = list(map(lambda item: {item: 1}, lst))  # 转换后:
print(ne_list)


# [{'hello': 1}, {'world': 1}, {'python': 1}, {'hello': 1}, {'python': 1}, {'java': 1}, {'hello': 1}, {'python': 1}, {'flask': 1}, {'world': 1}]


# 第三步：调用reduce实现相同单词的叠加
# 详细步骤
def func2(dict1, dict2):
    # dict1 作为叠加操作的返回字典{'aaa':1,'bbb':2}
    key = list(dict2.items())[0][0]  # 得到dict2 中key （单词：world）
    value = list(dict2.items())[0][1]  # 得到dict2 中value （1）
    # dict1.get(key, 0) ：如果dict1字典中有 key这个元素，那么取出来，0是设置的默认值
    dict1[key] = dict1.get(key, 0) + value  # 取出返回字典中的这个key对应的值，累加个 key对应的value，从value=0开始累加
    return dict1


print(reduce(func2, ne_list))
# 一行代码完成上述案例。
print(reduce(func2, map(lambda item: {item: 1}, str1.split(' '))))

# filter函数 过滤
lst1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 案例：输出列表中的偶数
print(filter(lambda n: n % 2 == 0, list1))  # 输出 <filter object at 0x000002156C81AB30> 可迭代对象
print(list(filter(lambda n: n % 2 == 0, lst1)))  # 输出 [2, 4, 6, 8, 10]   ，lst1 过滤之后，返回可迭代对象转换成新的list输出

# sorted函数 内置的函数排序
# 需要给某个复杂的序列排序，用lambda表达式， 相当于java中 根据key 给列表中的每个对象根据某个指定的key排序
lst = [
    {'name': '张三', 'age': 20, 'sex': '男'},
    {'name': '李四', 'age': 10, 'sex': '女'},
    {'name': '王五', 'age': 30, 'sex': '男'},
]

print(sorted(lst, key=lambda item: item['age'], reverse=True))
# 输出 [{'name': '王五', 'age': 30, 'sex': '男'}, {'name': '张三', 'age': 20, 'sex': '男'}, {'name': '李四', 'age': 10, 'sex': '女'}]


# 案例：字符串列表迭代器 排序
# 字符串序列 sorted() 根据 内存中字符串的 ASCII 码表的顺序排序
str_lst = ['hello', 'Java', 'Zoo', 'world']
print(sorted(str_lst))  # 输出：['Java', 'Zoo', 'hello', 'world'] 。 内存中字符串的 ASCII 码表的顺序排序，根据依此根据首字母，第二个字母...
# 这里注意一下：key=str.upper  没有括号，是内置函数 str的内置函数
print(sorted(str_lst, key=str.upper))  # 输出：['hello', 'Java', 'world', 'Zoo']

# 默认情况下，对字符串排序，是按照ASCII的大小比较的，由于’Z’ < ‘a’，结果，
# 大写字母Z会排在小写字母a的前面。所以，需要忽略大小写来比较两个字符串，
# 实际上就是先把字符串都变成大写（或者都变成小写），再比较。


print(sorted([36, 5, -12, 9, -21]))
# [-21, -12, 5, 9, 36]


print(sorted([36, 5, -12, 9, -21], key=abs))
# [5, 9, -12, -21, 36]